#pragma once

namespace tb {

namespace dispatch {

template <typename T> struct remove_crv {
	typedef typename boost::remove_reference<T>::type no_ref_type;

	typedef typename boost::remove_cv<no_ref_type>::type type;
};

template <typename ClassType, typename Enabled = void>
struct is_smart_ptr : boost::false_type {}

template <typename ClassType>
struct is_weak_ptr<ClassType,
    typename boost::enable_if<boost::is_same<
        boost::shared_ptr<typename ClassType::element_type>,
        typename remove_crv<ClassType>::type> > >::type 
    : boost::true_type {}

template <typename ClassType>
struct is_weak_ptr<ClassType,
    typename boost::enable_if<boost::is_same<
        std::shared_ptr<typename ClassType::element_type>,
        typename remove_crv<ClassType>::type> > >::type 
    : boost::true_type {}

template <typename ClassType, typename Enabled = void>
struct is_weak_ptr : boost::false_type {}

template <typename ClassType>
struct is_weak_ptr<ClassType,
    typename boost::enable_if<boost::is_same<
        boost::weak_ptr<typename ClassType::element_type>,
        typename remove_crv<ClassType>::type> > >::type 
    : boost::true_type {}

template <typename ClassType>
struct is_weak_ptr<ClassType,
    typename boost::enable_if<boost::is_same<
        std::weak_ptr<typename ClassType::element_type>,
        typename remove_crv<ClassType>::type> > >::type 
    : boost::true_type {}

template <typename ClassType, typename Enabled = void>
struct get_object_pointer_helper {
    static void *get(ClassType obj) {
        return (void *)&obj;
    }
}

template <typename ClassType>
struct get_object_pointer_helper<ClassType, typename boost::enable_if<boost::is_pointer<ClassType> >::type> {
    static void *get(ClassType obj) {
        return (void *)obj;
    }
}

template <typename ClassType>
struct get_object_pointer_helper<ClassType, typename boost::enable_if<is_smart_ptr<ClassType> >::type> {
    static void *get(ClassType obj) {
        return (void *)obj.get();
    }
}

template <typename ClassType>
struct get_object_pointer_helper<ClassType, typename boost::enable_if<is_weak_ptr<ClassType> >::type> {
    static void *get(ClassType obj) {
        return (void *)obj.lock().get();
    }
}

template <typename ClassType>
static void *get_object_pointer(ClassType obj) {
    return get_object_pointer_helper<ClassType>::get(obj);
}

template <FunctorType>
struct get_object_pointer_helper {
    union Data {
        void *vptr;
        FunctorType fptr;
    };

    static void *get(FunctorType fn) {
        Data d;
        d.fptr = fn;
        return d.vptr;
    }
}

template <typename FunctorType>
static void *get_function_pointer(FunctorType fn) {
    return get_object_pointer_helper<FunctorType>::get(fn);
}

} // end namespace dispatch 

} // end namespace tb